package com.tosee.dao.allocine.impl;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.lang.StringUtils;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.Namespace;
import org.jdom2.input.SAXBuilder;
import org.springframework.stereotype.Service;

import com.tosee.dao.allocine.IAllocineDao;
import com.tosee.model.allocine.AlloActeur;
import com.tosee.model.allocine.AlloEpisode;
import com.tosee.model.allocine.AlloRecherche;
import com.tosee.model.allocine.AlloSaison;
import com.tosee.model.allocine.AlloSerie;
import com.tosee.utils.ConstantesAllocine;

@Service
public class AllocineDao implements IAllocineDao {

    public AllocineDao() {

    }

    @Override
    public Document getInfo(Map<String, String> _parametres, String _url) {
        // Instantiate an HttpClient
        HttpClient client = new HttpClient();

        // Instantiate a GET HTTP method
        PostMethod method = new PostMethod(_url);
        method.setRequestHeader("Content-type", "text/xml; charset=ISO-8859-1");

        if(_parametres != null && CollectionUtils.isNotEmpty(_parametres.keySet())) {
            NameValuePair[] tabNameValuePair = new NameValuePair[_parametres.keySet().size()];
            int i = 0;
            for(String key : _parametres.keySet()) {
                tabNameValuePair[i] = new NameValuePair(key, _parametres.get(key));
                i++;

            }

            method.setQueryString(tabNameValuePair);

            try {
                int statusCode = client.executeMethod(method);

                System.out.println("Status Code = " + statusCode);
                System.out.println("QueryString>>> " + method.getQueryString());
                System.out.println("Status Text>>>" + HttpStatus.getStatusText(statusCode));

                // Get data as a String
                System.out.println(method.getResponseBodyAsString());

                SAXBuilder sxb = new SAXBuilder();
                Document document = null;
                try {
                    // On crée un nouveau document JDOM avec en argument le fichier XML
                    // Le parsing est terminé ;)
                    document = sxb.build(method.getResponseBodyAsStream());
                } catch (Exception e) {
                }

                // Onb parse le document XML ainsi récupéré afin d'en déduire une MAP
                return document;

            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                method.releaseConnection();
            }
        }
        return null;
    }

    /**
     * Methde de parsing d'un document pour construction d'info série
     * 
     * @param document
     * @return
     */
    public AlloRecherche parseDocumentToResultListSeries(Document _document) {
        Element racine = null;
        Namespace ns = ConstantesAllocine.NAMESPACE;
        // Map<String, Object> mapRetour = new HashMap<String, Object>();
        AlloSerie alloSerie = null;
        AlloRecherche recherche = null;
        if(_document != null) {
            recherche = new AlloRecherche();
            racine = _document.getRootElement();
            recherche.setPage(parseElementValueToInteger(racine.getChildText(ConstantesAllocine.PARSE_ELEMENT_PAGE,
                    ConstantesAllocine.NAMESPACE)));
            recherche.setNombre(parseElementValueToInteger(racine.getChildText(ConstantesAllocine.PARSE_ELEMENT_COUNT,
                    ConstantesAllocine.NAMESPACE)));
            recherche.setNbResultat(parseElementValueToInteger(racine.getChildText(
                    ConstantesAllocine.PARSE_ELEMENT_TOTALRESULT, ConstantesAllocine.NAMESPACE)));
            recherche.setListeSerie(new ArrayList<AlloSerie>());
            List<Element> listSerie = racine.getChildren(ConstantesAllocine.PARSE_ELEMENT_TVSERIES,
                    ConstantesAllocine.NAMESPACE);
            for(Element serieTemp : listSerie) {
                alloSerie = parseElementToAlloSerie(serieTemp, ns);
                recherche.getListeSerie().add(alloSerie);
            }
        }
        return recherche;
    }

    @Override
    public AlloSerie parseDocumentToResultSerie(Document _document) {

        Namespace ns = ConstantesAllocine.NAMESPACE;
        Element racine = null;

        AlloSerie alloSerie = null;

        if(_document != null) {
            racine = _document.getRootElement();
            alloSerie = parseElementToAlloSerie(racine, ns);
        }
        return alloSerie;
    }

    @Override
    public AlloSaison parseDocumentToResultSaison(Document _document) {
        Element racine = null;
        Namespace ns = ConstantesAllocine.NAMESPACE;

        AlloSaison alloSaison = null;

        if(_document != null) {
            racine = _document.getRootElement();
            alloSaison = parseElementToAlloSaison(racine, ns);
        }
        return alloSaison;
    }

    @Override
    public AlloEpisode parseDocumentToResultEpisode(Document _document) {
        Element racine = null;
        Namespace ns = ConstantesAllocine.NAMESPACE;

        AlloEpisode alloEpisode = null;

        if(_document != null) {
            racine = _document.getRootElement();
            alloEpisode = parseElementToAlloEpisode(racine, ns);
        }

        return alloEpisode;
    }

    /**
     * Parsing de la valeur d'un element en int
     */
    public static Integer parseElementValueToInteger(String _elementValue) {
        Integer retour = null;
        if(StringUtils.isNotBlank(_elementValue)) {
            retour = Integer.parseInt(_elementValue);
        }
        return retour;
    }

    /**
     * Parsing d'un element en alloepisode
     * 
     * @param _element L'element à parser
     * @param _ns le namespace
     */
    private static AlloEpisode parseElementToAlloEpisode(Element _element, Namespace _ns) {
        AlloEpisode retour = null;
        if(_element != null) {
            retour = new AlloEpisode();

            Element elemSerieParent = _element.getChild(ConstantesAllocine.PARSE_ELEMENT_PARENT_SERIE, _ns);
            if(elemSerieParent != null) {
                retour.setIdSerie(parseElementValueToInteger(elemSerieParent
                        .getAttributeValue(ConstantesAllocine.PARSE_ATTRIBUTE_CODE)));
            }
            Element elemSaisonParent = _element.getChild(ConstantesAllocine.PARSE_ELEMENT_PARENT_SAISON, _ns);
            if(elemSaisonParent != null) {
                retour.setIdSaison(parseElementValueToInteger(elemSaisonParent
                        .getAttributeValue(ConstantesAllocine.PARSE_ATTRIBUTE_CODE)));
            }
            retour.setCode(parseElementValueToInteger(_element
                    .getAttributeValue(ConstantesAllocine.PARSE_ATTRIBUTE_CODE)));
            retour.setNumeroSaison(parseElementValueToInteger(_element.getChildText(
                    ConstantesAllocine.PARSE_ELEMENT_EPISODENUMSAISON, _ns)));
            retour.setNumeroSerie(parseElementValueToInteger(_element.getChildText(
                    ConstantesAllocine.PARSE_ELEMENT_EPISODENUMSERIE, _ns)));
            String article = _element.getChildText(ConstantesAllocine.PARSE_ELEMENT_TITLEVO_ARTICLE, _ns);
            String titreVO = _element.getChildText(ConstantesAllocine.PARSE_ELEMENT_TITLEVO, _ns);
            StringBuilder sbTitre = new StringBuilder();
            if(StringUtils.isNotBlank(article)) {
                sbTitre.append(article);
            }
            if(StringUtils.isNotBlank(titreVO)) {
                sbTitre.append(titreVO);
            }
            retour.setTitreVO(sbTitre.toString());
            String titre = _element.getChildText(ConstantesAllocine.PARSE_ELEMENT_TITLE, _ns);

            retour.setTitre(StringUtils.isNotBlank(titre) ? titre : sbTitre.toString());

            retour.setSynopsis(_element.getChildText(ConstantesAllocine.PARSE_ELEMENT_SYNOPSIS, _ns));
        }
        return retour;
    }

    /**
     * Parsing d'un element en alloepisode
     * 
     * @param _element L'element à parser
     * @param _ns le namespace
     */
    private static AlloSaison parseElementToAlloSaison(Element _element, Namespace _ns) {
        AlloSaison retour = null;
        AlloEpisode alloEpisode = null;
        if(_element != null) {
            retour = new AlloSaison();

            Element elemSerieParent = _element.getChild(ConstantesAllocine.PARSE_ELEMENT_PARENT_SERIE, _ns);
            if(elemSerieParent != null) {
                retour.setIdSerie(parseElementValueToInteger(elemSerieParent
                        .getAttributeValue(ConstantesAllocine.PARSE_ATTRIBUTE_CODE)));
            }
            retour.setCode(parseElementValueToInteger(_element
                    .getAttributeValue(ConstantesAllocine.PARSE_ATTRIBUTE_CODE)));
            retour.setNumero(parseElementValueToInteger(_element.getChildText(
                    ConstantesAllocine.PARSE_ELEMENT_SAISONNUM, _ns)));
            retour.setNbEpisode(parseElementValueToInteger(_element.getChildText(
                    ConstantesAllocine.PARSE_ELEMENT_NBEPISODE, _ns)));
            retour.setAnneeDebut(_element.getChildText(ConstantesAllocine.PARSE_ELEMENT_YEARSTART, _ns));
            retour.setAnneeFin(_element.getChildText(ConstantesAllocine.PARSE_ELEMENT_YEAREND, _ns));

            Element episodeList = _element.getChild(ConstantesAllocine.PARSE_ELEMENT_LISTEPISODE, _ns);
            if(episodeList != null) {
                List<Element> listeEpisode = episodeList.getChildren(ConstantesAllocine.PARSE_ELEMENT_SAISON, _ns);
                if(CollectionUtils.isNotEmpty(listeEpisode)) {
                    for(Element episodeTemp : listeEpisode) {
                        alloEpisode = parseElementToAlloEpisode(episodeTemp, _ns);
                        retour.getListeEpisode().add(alloEpisode);
                    }
                }
            }
        }
        return retour;
    }

    /**
     * Parsing d'un element en alloacteur
     * 
     * @param _element L'element à parser
     * @param _ns le namespace
     */
    private static AlloActeur parseElementToAlloActeur(Element _element, Namespace _ns) {
        AlloActeur retour = null;

        Element person = null;
        if(_element != null) {
            retour = new AlloActeur();

            retour.setRole(_element.getChildText(ConstantesAllocine.PARSE_ELEMENT_ROLE, _ns));
            retour.setActivite(_element.getChildText(ConstantesAllocine.PARSE_ELEMENT_ACTIVITY, _ns));

            person = _element.getChild(ConstantesAllocine.PARSE_ELEMENT_PERSON, _ns);
            retour.setCode(parseElementValueToInteger(person.getAttributeValue(ConstantesAllocine.PARSE_ATTRIBUTE_CODE)));
            retour.setNom(person.getChildText(ConstantesAllocine.PARSE_ELEMENT_NAME, _ns));
        }
        return retour;
    }

    /**
     * Parsing d'un element en AlloSerie
     * 
     * @param _element L'element à parser
     * @param _ns le namespace
     */
    private static AlloSerie parseElementToAlloSerie(Element _element, Namespace _ns) {
        AlloSerie retour = null;
        AlloSaison alloSaison = null;
        AlloActeur alloActeur = null;

        if(_element != null) {
            retour = new AlloSerie();
            retour.setCode(parseElementValueToInteger(_element
                    .getAttributeValue(ConstantesAllocine.PARSE_ATTRIBUTE_CODE)));
            retour.setTitreVo(_element.getChildText(ConstantesAllocine.PARSE_ELEMENT_TITLEVO, _ns));
            retour.setTitre(_element.getChildText(ConstantesAllocine.PARSE_ELEMENT_TITLE, _ns));
            retour.setAnneeDebut(_element.getChildText(ConstantesAllocine.PARSE_ELEMENT_YEARSTART, _ns));
            retour.setAnneeFin(_element.getChildText(ConstantesAllocine.PARSE_ELEMENT_YEAREND, _ns));
            retour.setFormatDuree(_element.getChildText(ConstantesAllocine.PARSE_ELEMENT_FORMATTIME, _ns));

            Element seasonList = _element.getChild(ConstantesAllocine.PARSE_ELEMENT_LISTSAISON, _ns);
            if(seasonList != null) {
                List<Element> listeSaison = seasonList.getChildren(ConstantesAllocine.PARSE_ELEMENT_SAISON, _ns);
                if(CollectionUtils.isNotEmpty(listeSaison)) {
                    for(Element saisonTemp : listeSaison) {
                        alloSaison = parseElementToAlloSaison(saisonTemp, _ns);
                        retour.getListeSaison().add(alloSaison);
                    }
                }
            }
            Element casting = _element.getChild(ConstantesAllocine.PARSE_ELEMENT_CASTING, _ns);
            if(casting != null) {
                List<Element> listeActeur = casting.getChildren(ConstantesAllocine.PARSE_ELEMENT_CASTMEMBER, _ns);
                if(CollectionUtils.isNotEmpty(listeActeur)) {
                    for(Element acteurTemp : listeActeur) {
                        alloActeur = parseElementToAlloActeur(acteurTemp, _ns);
                        retour.getListeActeur().add(alloActeur);
                    }
                }
            }
        }
        return retour;
    }
}
